package main

import (
	"errors"
	"fmt"
)

/**
任何一个函数的定义，都有一个 func 关键字，用于声明一个函数，就像使用 var 关键字声明一个变量一样；
然后紧跟的 main 是函数的名字，命名符合 Go 语言的规范即可，比如不能以数字开头；
main 函数名字后面的一对括号 () 是不能省略的，括号里可以定义函数使用的参数，这里的 main 函数没有参数，所以是空括号 () ；
括号 () 后还可以有函数的返回值，因为 main 函数没有返回值，所以这里没有定义；
最后就是大括号 {} 函数体了，你可以在函数体里书写代码，写该函数自己的业务逻辑。
*/
//func main() {
//	v := sum(1,2)
//	fmt.Println(v)
//}

func sum(a int, b int) int {
	return a + b
}

// 如果参数都是一个类型，也可以这样写
func sum2(a, b int) int {
	return a + b
}

// 方法的多值返回
/**
1.如果有多个返回值，则返回值类型应该用括号括起来
2.
*/
func sum3(a, b int) (int, error) {
	if a < 0 || b < 0 {
		return 0, errors.New("a,b不能是负数")
	}
	return a + b, nil
}

// 函数有多值返回的时候，需要有多个变量接收它的值
/**
如果有的函数的返回值不需要，可以使用下划线 _ 丢弃它
result,_ := sum(1, 2)
*/
//func main() {
//	result,err := sum3(1, 2)
//	if err!=nil {
//		fmt.Println(err)
//	}else {
//		fmt.Println(result)
//	}
//}

// 命名返回参数
func sum5(a, b int) (sum int, err error) {
	if a < 0 || b < 0 {
		return 0, errors.New("a或者b不能是负数")
	}
	sum = a + b
	err = nil
	return
}

// 可变参数
/**
可变参数，就是函数的参数数量是可变的，比如最常见的 fmt.Println 函数。
同样一个函数，可以不传参数，也可以传递一个参数，也可以两个参数，也可以是多个等等，
定义可变参数，只要在参数类型前加三个点 … 即可
*/
func sum1(params ...int) int {
	sum := 0
	for _, i := range params {
		sum += i
	}
	return sum
}

//func main() {
//	fmt.Println(sum1(1,2))
//	fmt.Println(sum1(1,2,3))
//	fmt.Println(sum1(1,2,3,4))
//}

// 包级函数
/**
不管是自定义的函数 sum、sum1，还是我们使用到的函数 Println，都会从属于一个包，也就是 package。sum 函数属于 main 包，Println 函数属于 fmt 包。
同一个包中的函数哪怕是私有的（函数名称首字母小写）也可以被调用。如果不同包的函数要被调用，那么函数的作用域必须是公有的，也就是函数名称的首字母要大写，比如 Println。
在后面的包、作用域和模块化的课程中我会详细讲解，这里可以先记住：
函数名称首字母小写代表私有函数，只有在同一个包中才可以被调用；
函数名称首字母大写代表公有函数，不同的包也可以调用；
任何一个函数都会从属于一个包。
*/

// 匿名函数和闭包
/**
顾名思义，匿名函数就是没有名字的函数，这是它和正常函数的主要区别。
在下面的示例中，变量 sum2 所对应的值就是一个匿名函数。需要注意的是，这里的 sum2 只是一个函数类型的变量，并不是函数的名字。
*/

// 匿名函数
//func main() {
//	method:=func(a,b int)int{
//		return a+b
//	}
//	fmt.Println(method(1,2))
//}

// 闭包 更重要的是，在函数内定义的内部函数，可以使用外部函数的变量等，这种方式也称为闭包。
func main() {
	method := closure()
	fmt.Println(method())
	fmt.Println(method())
	fmt.Println(method())
}

func closure() func() int {
	i := 0
	return func() int {
		i++
		return i
	}
}
